/**
 * Fichier InitialisationBase.java : Définition de classe
 * fr.unice.gnpt.core.init.data.InitialisationBase : Création et initialisation
 * de la base de données
 * 
 * Auteurs : Groupe GNPT : Gastinel, Nicolas, Pellegrino, Trovato
 * 
 * $Id$
 */
package fr.unice.gnpt.core.init;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import fr.unice.gnpt.Main;
import fr.unice.gnpt.core.Cours;
import fr.unice.gnpt.core.Enseignant;
import fr.unice.gnpt.core.Enseignement;
import fr.unice.gnpt.core.Service;
import fr.unice.gnpt.core.dao.DaoException;
import fr.unice.gnpt.core.dao.DaoGenerique;
import fr.unice.gnpt.core.dao.connexion.Connexion;
import fr.unice.gnpt.core.dao.connexion.ConnexionException;
import fr.unice.gnpt.core.dao.factory.FabriqueDao;
import fr.unice.gnpt.core.init.data.LecteurSax;

/**
 * Classe chargée d'initialiser la base de données avec les valeurs par défaut.
 * 
 * @author gnpt
 * @version 0.2.$LastChangedRevision$
 */
public class InitialisationBase {

	LecteurSax sax;

	/**
	 * Constructeur de la classe d'initialisation de la base de données
	 */
	public InitialisationBase() {
		this.sax = new LecteurSax();
	}

	/**
	 * Accesseur pour le LecteurSax de la classe
	 * 
	 * @return le LecteurSax de la classe.
	 */
	public LecteurSax getLecteurSax() {
		return this.sax;
	}

	/**
	 * Remplit la base de données avec les informations de base
	 * 
	 * @throws DaoException
	 */
	public void remplirBase() throws DaoException {
		LecteurSax l = this.getLecteurSax();
		try {
			XMLReader r = XMLReaderFactory.createXMLReader();
			SAXParserFactory spf = SAXParserFactory.newInstance();
			l.setParent(spf.newSAXParser().getXMLReader());

			r.setContentHandler(l);

			r.parse(this
					.getInputSourceDepuisNomFichier("data/DonneesCours.xml"));
			r
					.parse(this
							.getInputSourceDepuisNomFichier("data/DonneesEnseignants.xml"));
			r
					.parse(this
							.getInputSourceDepuisNomFichier("data/DonneesServices.xml"));
		} catch (SAXException e) {
			Main.getJournal().logException(e);
		} catch (IOException e) {
			Main.getJournal().logException(e);
		} catch (ParserConfigurationException e) {
			Main.getJournal().logException(e);
		}

		FabriqueDao fab = FabriqueDao.getFabriqueDao();

		this.enregistrerDonnees(fab.getDaoEnseignant(), this.sax
				.getCollectionEnseignants());

		this.enregistrerDonnees(fab.getDaoCours(), this.sax
				.getCollectionCours());

		this.enregistrerDonnees(fab.getDaoService(), this.sax
				.getCollectionServices());
		
		for (Service s : this.sax.getCollectionServices()) {
			Enseignant e = s.getEnseignant();
			Collection<Service> old = e.getServices();
			old.add(s);
			e.setServices(new ArrayList<Service>(old));
			if (s instanceof Enseignement) {
				Cours c = ((Enseignement) s).getCours();
				Collection<Enseignement> olde = c.getEnseignements();
				olde.add((Enseignement) s);
				c.setEnseignements(new ArrayList<Enseignement>(olde));
			}
		}
		
		this.miseAJourDonnees(fab.getDaoEnseignant(), this.sax.getCollectionEnseignants());
		this.miseAJourDonnees(fab.getDaoCours(), this.sax.getCollectionCours());
	}

	/**
	 * Construit un objet InputSource depuis un nom de fichier faisant partie de
	 * ce package
	 * 
	 * @param nomFichier
	 *            le nom du fichier à ouvrir.
	 * @return l'objet InputSource obtenu à partir de ce nom de fichier.
	 */
	public InputSource getInputSourceDepuisNomFichier(String nomFichier) {
		if (nomFichier == null)
			return null;
		Class<?> initClass = InitialisationBase.class;
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		try {
			// On obtient un ByteStream
			is = initClass.getResourceAsStream(nomFichier);
			// Qui est converti en CharacterStream (pour unicode)
			isr = new InputStreamReader(is, "UTF-8");
			// Puis on bufferise (question efficacité)
			br = new BufferedReader(isr);
		} catch (UnsupportedEncodingException e) {
			Main.getJournal().logException(e,
					"Le charset UTF-8 n'est pas supporté par la JVM.", true,
					true);
			return null;
		}
		return new InputSource(br);
	}

	private <T> void enregistrerDonnees(DaoGenerique<T, ?> dao,
			Collection<T> collection) {
		
		Connexion<?> connexion = dao.getConnexion();

		try {
		connexion.ouvrir();
		connexion.beginTransaction();

		for (T entite : collection) {
			try {
				dao.create(entite);
			} catch (DaoException e) {
				String msg = "Dao: Echec de create sur l'entité '"
						+ entite.toString() + "'.";
				Main.getJournal().logException(e, msg, false, true);
			}
		}

		connexion.commitTransaction();
		connexion.fermer();
		} catch (ConnexionException e) {
			// Erreur lors des connexion/transaction
			Main.getJournal().logException(e,
					"Erreur de connexion/transaction", true, true);
		}
	}

	private <T> void miseAJourDonnees(DaoGenerique<T, ?> dao,
			Collection<T> collection) {
		
		Connexion<?> connexion = dao.getConnexion();

		try {
		connexion.ouvrir();
		connexion.beginTransaction();

		for (T entite : collection) {
			try {
				dao.update(entite);
			} catch (DaoException e) {
				String msg = "Dao: Echec de create sur l'entité '"
						+ entite.toString() + "'.";
				Main.getJournal().logException(e, msg, false, true);
			}
		}

		connexion.commitTransaction();
		connexion.fermer();
		} catch (ConnexionException e) {
			// Erreur lors des connexion/transaction
			Main.getJournal().logException(e,
					"Erreur de connexion/transaction", true, true);
		}
	}
}
